package com.cdzs.twocamera;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.hardware.usb.UsbDevice;
import android.media.FaceDetector;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.cdzs.twocamera.constant.Constant;
import com.cdzs.twocamera.dialog.PwdInputDialog;
import com.cdzs.twocamera.keeplive.JobSchedulerManager;
import com.cdzs.twocamera.myinterface.NettyListener;
import com.cdzs.twocamera.myinterface.OnPasswordInputFinish;
import com.cdzs.twocamera.tcp.NettyClient;
import com.cdzs.twocamera.util.ArrayMergeUtil;
import com.cdzs.twocamera.util.ByteUtil;
import com.cdzs.twocamera.util.DateFormatUtil;
import com.cdzs.twocamera.util.NumberUtil;
import com.cdzs.twocamera.util.SPUtils;
import com.cdzs.twocamera.util.TcpAssembleUtil;
import com.cdzs.twocamera.util.WriteLogUtil;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;
import com.iflytek.cloud.util.ResourceUtil;
import com.sanquan.boardcomm.DoorAccessCommManager;
import com.sanquan.boardcomm.GpioController;
import com.sanquan.boardcomm.ISerialEvent;
import com.sanquan.boardcomm.LedLightManager;
import com.serenegiant.common.BaseActivity;
import com.serenegiant.usb.DeviceFilter;
import com.serenegiant.usb.IFrameCallback;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
import com.serenegiant.usb.UVCCamera;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android_serialport_api.CRC16M;
import de.hdodenhof.circleimageview.CircleImageView;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import timber.log.Timber;

public class MainActivitySurface extends BaseActivity implements NettyListener, ISerialEvent, DoorAccessCommManager.OnBoardCommReceiveListener {

    private static final boolean DEBUG = true;
    private static final String TAG = "MainActivity";
    private static final int SHOW_TIME = 1;
    private static final int REMOVE_PERSON_ID = 3;

    private List<UsbDevice> mUsbDeviceList;

    private final Object mSync = new Object();

    // for accessing USB and USB camera
    private USBMonitor mUSBMonitor;
    private UVCCamera mUVCCamera;
    private UVCCamera mUVCCameraInfrared;

    private SurfaceView mUVCCameraView;
    private SurfaceView mUVCCameraViewInfrared;

    private Surface mPreviewSurface;
    private Surface mPreviewSurfaceInfrared;
    private boolean isActive, isPreview;
    private boolean isActiveInfrared, isPreviewInfrared;

    private CircleImageView mImageView;
    private ScheduledExecutorService mScheduledExecutorService;
    private byte[] heartBeatBytes;
    private byte[] picDataBytes;
    private int personIdIndex;
    private int personNameIndex;
    private int dataLength = 0;
    private byte[] data = new byte[0];

    // JobService，执行系统任务
    private JobSchedulerManager mJobManager;

    private List<String> personIdList = new ArrayList<>();

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SHOW_TIME:
                    long time = System.currentTimeMillis();
                    // 显示系统时间
                    tvSystemTime.setText(DateFormatUtil.format(time, DateFormatUtil.DateFormatEnum.hms));
                    tvSystemDate.setText(DateFormatUtil.format(time, DateFormatUtil.DateFormatEnum.ymdWeek));
                    if ((time - systemStartRunTime) > 600 * 1000) {
                        if (!isSkip) {
                            isSkip = true;
                            Log.d("Thread", "页面跳转");
                            startActivity(new Intent(MainActivitySurface.this, VideoActivity.class));
                        }
                    }
                    break;
                case REMOVE_PERSON_ID:
                    // 从集合中删除人员 ID
                    if (personIdList.size() > 0) {
                        personIdList.remove(0);
                    }
                    break;
                default:
                    break;
            }
        }
    };
    private Bitmap receiveBitmap;

    // UI 界面三种情况对应的显示效果
    private RelativeLayout rlSuccess;
    private RelativeLayout rlStranger;

    private TextView tvNameResult;
    private TextView tvIdResult;

    private byte[] personNameByte;
    private byte[] personIDByte;
    private boolean isDisconnected = false;

    private String texts;
    // 默认本地发音人
    public static String voicerLocal = "xiaofeng";
    //缓冲进度
    private int mPercentForBuffering = 0;
    //播放进度
    private int mPercentForPlaying = 0;

    // 引擎类型
    //private String mEngineType = SpeechConstant.TYPE_LOCAL;
    private FrameLayout frameLayoutOfSurfaceContainer;
    private FrameLayout frameLayoutOfInfraredSurfaceContainer;

    private RelativeLayout rlNetError;
    private RelativeLayout rlUSBError;

    private boolean isStart = true;
    private long startTime;
    private long endTime;
    private RelativeLayout rl_set;

    private List<String> contentList;
    private int count = 0;
    private boolean isSend = false;
    private int realFaceNum;
    private boolean hasDetected;
    private ImageView tempImage;
    private Paint paint;
    private Bitmap zero;
    private float eyesDistance;
    private long systemStartRunTime;
    private boolean isSkip = false;
    private Thread timeThread;
    private Timer mTimerForLED;
    private RemovePersonIDThread removePersonIDThread;
    private PwdInputDialog dialog;
    private boolean fireMode = false;
    private boolean peakMode = false;
    private boolean isVisibleLightPicCollected = false;

    @Override
    public void onBoardHeartbeat(byte[] bytes, byte[] bytes1, byte[] bytes2, byte[] bytes3, byte[] bytes4) {

    }

    @Override
    public void onBoardPostAccessRecord(byte[] bytes, byte[] bytes1, byte[] bytes2, byte[] bytes3, byte[] bytes4, byte b) {

    }

    @Override
    public void onBoardLockTongueState(byte b, byte[] bytes) {

    }

    @Override
    public void onBoardKeyDown(byte b, byte[] bytes) {

    }

    @Override
    public void onBoardPowerSet(byte[] bytes) {

    }

    @Override
    public void onActionSuccess() {

    }

    @Override
    public void onActionFailed() {

    }

    @Override
    public void onMcuUpgradeStart() {

    }

    @Override
    public void onMcuUpgradeProgress(int i) {

    }

    @Override
    public void onMcuUpgradeSuccess() {

    }

    @Override
    public void onMcuUpgradeFailed(int i) {

    }

    @Override
    public void onMcuWiegandData(byte[] bytes, byte b) {

    }

    @Override
    public void onMcuReadM1Card(byte[] bytes, byte b) {

    }

    @Override
    public void onMcuReadM1CardBank(byte[] bytes) {

    }


    //====================== 以下四个方法为串口方法=========================
    @Override
    public void onSerialSuccess() {
        Log.d(TAG, "onSerialFail: 串口成功打开，可以开启门禁");
    }

    @Override
    public void onSerialFail(String s) {
        Log.d(TAG, "onSerialFail: 串口无法打开，无法开启门禁");
    }

    @Override
    public void onCommRecv(String s) {

    }

    @Override
    public void onCommSend(String s) {

    }

    /**
     * 用于定时的线程，每秒钟发送一个
     */
    public class TimeThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (true) {
                try {
                    Thread.sleep(1000);
                    Message msg = Message.obtain();
                    msg.what = SHOW_TIME;
                    handler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 用于定时的线程，每秒钟发送一个
     */
    public class RemovePersonIDThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (true) {
                try {
                    Thread.sleep(3000);
                    Message msg = Message.obtain();
                    msg.what = REMOVE_PERSON_ID;
                    handler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 标记图片是否接收完成，接收完成之后，在发送最新的一帧到服务器
     */
    private boolean isReceived = false;

    private ByteArrayOutputStream baos;
    private ByteArrayOutputStream baosInfrared;
    private byte[] picBytes;
    private byte[] picBytesInfrared;

    // 显示系统时间
    private TextView tvSystemTime;
    private TextView tvSystemDate;

    // 语音合成对象
    private SpeechSynthesizer mTts;

    private boolean isFirstAttachUSB = true;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.d("life", "onCreate: ");

        setContentView(R.layout.activity_main_surface);

        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
        decorView.setSystemUiVisibility(uiOptions);

        // 从服务器或本地获取系统配置信息
        setSystemInfo();

        // 初始化控件
        initViewAndData();

        // 初始化摄像头
        initCamera();

        //初始化串口，用于设置开关量信号，打开门禁
        //initSerialPort();

        // 初始化系统时间，ID移除线程
        initThread();

//        以下为注册本地广播
//        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
//        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);

//        receiver.setINetStateListener(new NetworkReceiver.INetStateListener() {
//            @Override
//            public void netEnable() {
//                // 连接到服务器，在连接时，会判断连接状态，没有连接才会连接
//                connect();
//
//            }
//
//            @Override
//            public void netDisable() {
//                shutdown();
//                NettyClient.getInstance().setReconnectNum(0);
//                NettyClient.getInstance().disconnect();
//
//            }
//        });

        // 初始化 TCP 连接，并且连接到相应的服务器
        initTcpConnect();

        // 初始化通行语音对象
        initPassVoice();


//        sendHeatBeatPackage();
    }

    /**
     * 初始化通行语音合成对象，离线语音合成
     */
    private void initPassVoice() {
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(this, mTtsInitListener);
        texts = "认证通过";
    }

    /**
     * 初始化TCP，设置相应的状态监听器，并且连接到相应的服务器
     * 1、收到数据流的监听器
     * 2、网络连接状态的监听
     */
    private void initTcpConnect() {

        if (fireMode) {
            GpioController.getInstance().unLockGate();
        } else {
            NettyClient.getInstance().setListener(this);

            // 连接到服务器，在连接时，会判断连接状态，没有连接才会连接
            connect();
        }
    }

    /**
     * 初始化并开启线程
     * 1、定时线程，用于展示系统时间
     * 2、移除用户 Id 线程，3 秒定时移除用户Id
     * 3、定时器，每隔十秒关闭一次 LED 补光灯
     */
    private void initThread() {

        timeThread = new TimeThread();
        timeThread.start();
        removePersonIDThread = new RemovePersonIDThread();
        removePersonIDThread.start();
        mTimerForLED = new Timer();
        mTimerForLED.schedule(new TimerTask() {

            @Override
            public void run() {

                GpioController.getInstance().turnOffLed();
            }
        }, 0, 5000);
    }

    /**
     * 初始化硬件串口，用于设置设置开关量信号，开关门禁
     */
    private void initSerialPort() {
        DoorAccessCommManager.getInstance().openComm("/dev/ttysWK2", 115200, MainActivitySurface.this);
        DoorAccessCommManager.getInstance().setOnBoardCommRequest(MainActivitySurface.this);
    }

    /**
     * 从服务起获取相应系统配置后，写入本地配置文件
     */
    private void setSystemInfo() {


        //todo 获取服务器配置信息，从这里读取服务器在配置文件，在本地进行存储
        SPUtils.setSharedStringData("ip", "192.168.9.10");
        SPUtils.setSharedIntData("server_port", 7777);

        // 语速、音调、音量
        SPUtils.setSharedStringData("SPEED", "50");
        SPUtils.setSharedStringData("PITCH", "50");
        SPUtils.setSharedStringData("VOLUME", "50");
        SPUtils.setSharedStringData("VOICE_NAME", "xiaofeng");

        contentList = new ArrayList<>();
//        contentList.add("一路顺风");
//        contentList.add("出去玩的开心");
//        contentList.add("旅途愉快");
        contentList.add("认证通过");

        systemStartRunTime = System.currentTimeMillis();

        fireMode = SPUtils.getSharedBooleanData("fireMode");
        peakMode = SPUtils.getSharedBooleanData("peakMode");
    }

    /**
     * 打开补光灯
     *
     * @param lightID LedLightManager.LED_LIGHT_0 LedLightManager.LED_LIGHT_1
     */
    public void openLight(int lightID) {
        LedLightManager.triggerLedOn(lightID);

    }

    /**
     * 关闭补光灯
     *
     * @param lightID LedLightManager.LED_LIGHT_0 LedLightManager.LED_LIGHT_1
     */
    public void closeLight(int lightID) {
        LedLightManager.triggerLedOff(lightID);
    }

    /**
     * 发送心跳包
     */
    public void sendHeatBeatPackage() {

        // 自定义心跳，每隔20秒向服务器发送心跳包，在线程池中进行
        mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        mScheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                heartBeatBytes = ArrayMergeUtil.byteMergerAll(
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(16)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt())
                );

                NettyClient.getInstance().sendMsgToServer(heartBeatBytes, new ChannelFutureListener() {    //3
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {                //4
                            Timber.d("Write heartbeat successful");

                        } else {
                            Timber.e("Write heartbeat error");
                            WriteLogUtil.writeLogByThread("heartbeat error");
                        }
                    }
                });
            }
        }, 3, 3, TimeUnit.SECONDS);
    }

    private void initViewAndData() {

        //startService(new Intent(MainActivitySurface.this, SystemKeepLiveService.class));
        mJobManager = JobSchedulerManager.getJobSchedulerInstance(this);
        mJobManager.startJobScheduler();

//        获取屏幕宽高
//        DisplayMetrics dm = getResources().getDisplayMetrics();
//        Log.d("123", "initViewAndData: " + dm.heightPixels);
//        Log.d("123", "initViewAndData: " + dm.widthPixels);

        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        paint.setStyle(Paint.Style.STROKE);//设置话出的是空心方框而不是实心方块

        mImageView = findViewById(R.id.mImageView);
        tvSystemTime = findViewById(R.id.tv_system_time);
        tvSystemDate = findViewById(R.id.tv_system_date);
        tempImage = findViewById(R.id.tempImage);

        rlSuccess = findViewById(R.id.rl_success);
        rlStranger = findViewById(R.id.rl_stranger);
        rlNetError = findViewById(R.id.rl_netError);
        rlUSBError = findViewById(R.id.rl_USBError);

        // 长按界面进入系统设置界面
        rl_set = findViewById(R.id.rl_set);
        rl_set.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
//
                dialog = new PwdInputDialog(MainActivitySurface.this, R.style.dialog);

                dialog.setOnFinishInput(new OnPasswordInputFinish() {
                    @Override
                    public void inputFinish() {
                        //交易逻辑什么的在这里写
                        if (dialog.getStrPassword().equals("111111")) {
                            Intent intent = new Intent(MainActivitySurface.this, SettingActivity.class);
                            dialog.dismiss();
                            startActivity(intent);
                        } else {
                            Toast.makeText(MainActivitySurface.this, "密码错误", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                dialog.show();

                return false;
            }
        });

        tvNameResult = findViewById(R.id.tv_name_result);
        tvIdResult = findViewById(R.id.tv_id_result);

    }

    /**
     * 初始化 USB 摄像头相关的 UI
     */
    private void initCamera() {

        frameLayoutOfInfraredSurfaceContainer = findViewById(R.id.frameLayoutOfInfraredSurfaceContainer);
        mUVCCameraViewInfrared = new SurfaceView(this);
        mUVCCameraViewInfrared.getHolder().addCallback(mSurfaceViewCallbackInfrared);
        frameLayoutOfInfraredSurfaceContainer.addView(mUVCCameraViewInfrared);

        mUVCCameraView = new SurfaceView(this);
        mUVCCameraView.getHolder().addCallback(mSurfaceViewCallback);
        frameLayoutOfSurfaceContainer = findViewById(R.id.frameLayoutOfSurfaceContainer);
        frameLayoutOfSurfaceContainer.addView(mUVCCameraView);

        mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);

        // 同步方法、获取访问 USB 的权限、注册之后，会检测一次 USB 是否 attach
        mUSBMonitor.register();

        // 获取 USB 设备的列表
        updateDevices();
    }

    @Override
    protected void onRestart() {
        super.onRestart();

        Log.d("life", "onRestart: ");

        isSkip = false;
        systemStartRunTime = System.currentTimeMillis();

        if (mUVCCamera != null) {
            mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);
        }

        if (mUVCCameraInfrared != null) {
            mUVCCameraInfrared.setFrameCallback(mIFrameCallbackInfrared, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        isReceived = true;
        Log.d("life", "onStart: ");

//        // 同步方法、获取访问 USB 的权限、注册之后，会检测一次 USB 是否 attach
//        mUSBMonitor.register();
//
//        // 获取 USB 设备的列表
//        updateDevices();

//        synchronized (mSync) {
//            if (mUVCCamera != null) {
//                mUVCCamera.startPreview();
//            }
//        }

//        synchronized (mSync) {
//            if (mUSBMonitor != null) {
//                mUSBMonitor.register();
//            }
//            // 获取 USB 设备的列表
//        }
//        updateDevices();
    }

    /**
     * 更新设备列表
     * 获取设备列表，该列表不可更改
     */
    public synchronized void updateDevices() {
        //下面注释代码表示在控制台打印连接设备列表
        //mUSBMonitor.dumpDevices();
        final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(this, com.serenegiant.uvccamera.R.xml.device_filter);
        mUsbDeviceList = mUSBMonitor.getDeviceList(filter.get(0));

        for (int i = 0; i < mUsbDeviceList.size(); i++) {
            Log.d("USBMonitor", "updateDevices: " + String.format("UVC Camera:(%x:%x:%s)", mUsbDeviceList.get(i).getVendorId(), mUsbDeviceList.get(i).getProductId(), mUsbDeviceList.get(i).getDeviceName()));
            Log.d("USBMonitor", "run: " + mUsbDeviceList.get(i).getProductId());
        }

//        // 判断传入 USB 设备权限、处理连接、绑定USB设备处理模块的处理模块
//        // 0 红外摄像头
//        // 1 自带摄像头
//        // 2 可见光摄像头
        new Thread() {
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < mUsbDeviceList.size(); i++) {
                    // 大摄像头---可见光
                    // 大摄像头---红外
                    // 小摄像头----可见光
                    // 小摄像头----红外
                    if (mUsbDeviceList.get(i).getProductId() == 25446
                            || mUsbDeviceList.get(i).getProductId() == 8499
                            || mUsbDeviceList.get(i).getProductId() == 33291
                            || mUsbDeviceList.get(i).getProductId() == 13180
                            || mUsbDeviceList.get(i).getProductId() == 4658
                            || mUsbDeviceList.get(i).getProductId() == 12341
                            || mUsbDeviceList.get(i).getProductId() == 1412
                            || mUsbDeviceList.get(i).getProductId() == 1413
                            || mUsbDeviceList.get(i).getDeviceName() == "/dev/bus/usb/001/039"
                            ) {

                        try {
                            Thread.sleep(500);//休眠3秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        mUSBMonitor.requestPermission(mUsbDeviceList.get(i));
                    }
                }
            }
        }.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("life", "onPause: ");
    }

    @Override
    protected void onStop() {
        if (DEBUG) {
            Log.v(TAG, "onStop:");
        }
        isReceived = false;
        Log.d("life", "onStop: ");
        mTimerForLED.cancel();
        GpioController.getInstance().turnOffLed();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        if (DEBUG) {
            Log.v(TAG, "onDestroy:");
        }
        Log.d("life", "onDestroy: ");
        synchronized (mSync) {

            mTimerForLED.cancel();

            isActive = isPreview = false;
            isActiveInfrared = isPreviewInfrared = false;

            if (mUVCCamera != null) {
                mUVCCamera.destroy();
                mUVCCamera = null;
            }
            if (mUVCCameraInfrared != null) {
                mUVCCameraInfrared.destroy();
                mUVCCameraInfrared = null;
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.destroy();
                mUSBMonitor = null;
            }
        }
        mUVCCameraView = null;
        mUVCCameraViewInfrared = null;

        releaseResource();

        super.onDestroy();
    }

    /**
     * 页面销毁时，释放页面相关资源
     * 1、关闭发送心跳包的线程池
     * 2、断开 tcp 的连接
     * 3、释放语音播报相关资源
     */
    private void releaseResource() {
        shutdown();
        NettyClient.getInstance().setReconnectNum(0);
        NettyClient.getInstance().disconnect();

        if (null != mTts) {
            mTts.stopSpeaking();
            // 退出时释放连接
            mTts.destroy();
        }
    }

    /**
     * 从 UI 容器中移除SurfaceView
     */
    public synchronized void removeSurfaceView() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                frameLayoutOfSurfaceContainer.removeView(mUVCCameraView);
                frameLayoutOfInfraredSurfaceContainer.removeView(mUVCCameraViewInfrared);
            }
        });
    }


    private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
        @Override
        public void onAttach(final UsbDevice device) {
            if (DEBUG) {
                Log.d("USBMonitor", "MainActivity onAttach:");
                Log.d("123", "MainActivity onAttach:");
            }

//            if(isFirstAttachUSB && !isDisconnected){
//                isFirstAttachUSB = false;
//                handler.post(new Runnable() {
//                    @Override
//                    public void run() {
//                        Log.d(TAG, "run: ");
//                        initCamera();
//                    }
//                });
//            }

            if (isDisconnected) {
                isDisconnected = false;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        initCamera();
                    }
                });
            }

            Toast.makeText(MainActivitySurface.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
            if (DEBUG) {
                Log.d("USBMonitor", "MainActivity onConnect:");
                Log.d("123", "MainActivity onConnect:");
            }
            synchronized (mSync) {
//                if (mUVCCamera != null) {
//                    mUVCCamera.destroy();
//                }
//                if (mUVCCameraInfrared != null) {
//                    mUVCCameraInfrared.destroy();
//                }
                isActive = isPreview = false;
                isActiveInfrared = isPreviewInfrared = false;
            }

            handler.post(new Runnable() {
                @Override
                public void run() {
                    rlUSBError.setVisibility(View.GONE);
                }
            });

            queueEvent(new Runnable() {
                @Override
                public void run() {
                    synchronized (mSync) {
                        // 摄像头---可见光
                        if (device.getProductId() == 8499
                                || device.getProductId() == 25446
                                || device.getProductId() == 4658
                                || device.getProductId() == 12341
                                || device.getProductId() == 1412
                                || device.getDeviceName() == "/dev/bus/usb/001/039") {
                            final UVCCamera camera = new UVCCamera();
                            Log.d("USBMonitor", "run: " + createNew);
                            Log.d("USBMonitor", "USBMonitor: " + ctrlBlock);
                            camera.open(ctrlBlock);
                            if (DEBUG) {
                                Log.d("USBMonitor", "MainActivity supportedSize:" + camera.getSupportedSize());
                            }
                            try {
                                camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
                            } catch (final IllegalArgumentException e) {
                                try {
                                    // fallback to YUV mode
                                    camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
                                } catch (final IllegalArgumentException e1) {
                                    Log.d("USBMonitor", "run: 预览设置异常");
                                    camera.destroy();
                                    return;
                                }
                            }
                            mPreviewSurface = mUVCCameraView.getHolder().getSurface();
                            if (mPreviewSurface != null) {
                                isActive = true;
                                camera.setPreviewDisplay(mPreviewSurface);

                                // 设置获取图像帧的回调
                                camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);

                                Log.d("USBMonitor", "run: 开启了预览");
                                camera.startPreview();
                                isPreview = true;
                            }
                            synchronized (mSync) {
                                mUVCCamera = camera;
                            }
                        }
                        // 摄像头---红外
                        if (device.getProductId() == 13180 || device.getProductId() == 33291 || device.getProductId() == 1413) {
                            final UVCCamera camera = new UVCCamera();
                            camera.open(ctrlBlock);
                            if (DEBUG) {
                                Log.i(TAG, "supportedSize:" + camera.getSupportedSize());
                            }
                            try {
                                camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG);
                            } catch (final IllegalArgumentException e) {
                                try {
                                    // fallback to YUV mode
                                    camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE);
                                } catch (final IllegalArgumentException e1) {
                                    camera.destroy();
                                    return;
                                }
                            }

                            mPreviewSurfaceInfrared = mUVCCameraViewInfrared.getHolder().getSurface();
                            if (mPreviewSurfaceInfrared != null) {
                                isActiveInfrared = true;
                                camera.setPreviewDisplay(mPreviewSurfaceInfrared);

                                // 设置获取图像帧的回调
                                camera.setFrameCallback(mIFrameCallbackInfrared, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);

                                camera.startPreview();
                                isPreviewInfrared = true;
                            }
                            synchronized (mSync) {
                                mUVCCameraInfrared = camera;
                            }
                        }
                    }
                }
            }, 0);
        }

        @Override
        public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
            if (DEBUG) {
                Log.d("USBMonitor", "MainActivity onDisconnect:");
                Log.d("123", "MainActivity onDisconnect:");
            }
            isDisconnected = true;
            handler.post(new Runnable() {
                @Override
                public void run() {
                    rlUSBError.setVisibility(View.VISIBLE);
                }
            });
            // XXX you should check whether the comming device equal to camera device that currently using
            queueEvent(new Runnable() {
                @Override
                public void run() {
                    synchronized (mSync) {

                        removeSurfaceView();

                        if (mUVCCamera != null) {
                            //mUSBMonitor.unregister();
                            mUVCCamera.destroy();
                            mUVCCamera = null;
                            Log.d("USBMonitor", "run: onDisconnect 调用close");
                            if (mPreviewSurface != null) {
                                mPreviewSurface.release();
                                mPreviewSurface = null;
                            }
                            if (mUVCCameraView != null) {
                                mUVCCameraView = null;
                            }
                            if (mPreviewSurface != null) {
                                mPreviewSurface = null;
                            }
                            isActive = isPreview = false;
                        }

                        if (mUVCCameraInfrared != null) {
                            mUVCCameraInfrared.destroy();
                            mUVCCameraInfrared = null;
                            if (mPreviewSurfaceInfrared != null) {
                                mPreviewSurfaceInfrared.release();
                                mPreviewSurfaceInfrared = null;
                            }
                            if (mUVCCameraViewInfrared != null) {
                                mUVCCameraViewInfrared = null;
                            }
                            isActiveInfrared = isPreviewInfrared = false;
                        }
                        mUSBMonitor = null;
                    }
                }
            }, 0);
        }

        @Override
        public void onDettach(final UsbDevice device) {
            if (DEBUG) {
                Log.d("USBMonitor", "MainActivity onDettach:");
                Log.d("123", "MainActivity onDettach:");
            }
            Toast.makeText(MainActivitySurface.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCancel(final UsbDevice device) {
        }
    };

    /**
     * 可见光摄像头 SurfaceView 创建回调
     */
    private final SurfaceHolder.Callback mSurfaceViewCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(final SurfaceHolder holder) {
            if (DEBUG) {
                Log.d("USBMonitor", "surfaceCreated:");
            }
        }

        @Override
        public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
            if ((width == 0) || (height == 0)) {
                return;
            }
            if (DEBUG) {
                Log.d("USBMonitor", "surfaceChanged:");
            }
            mPreviewSurface = holder.getSurface();
            synchronized (mSync) {
                if (isActive && !isPreview && (mUVCCamera != null)) {
                    mUVCCamera.setPreviewDisplay(mPreviewSurface);
                    mUVCCamera.startPreview();
                    isPreview = true;
                }
            }
        }

        @Override
        public void surfaceDestroyed(final SurfaceHolder holder) {
            if (DEBUG) {
                Log.v(TAG, "surfaceDestroyed:");
            }
            synchronized (mSync) {
                if (mUVCCamera != null) {
                    mUVCCamera.stopPreview();
                }
                isPreview = false;
            }
            mPreviewSurface = null;
        }
    };

    /**
     * 红外摄像头 SurfaceView 创建回调
     */
    private final SurfaceHolder.Callback mSurfaceViewCallbackInfrared = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(final SurfaceHolder holder) {
            if (DEBUG) {
                Log.v(TAG, "surfaceCreated:");
            }
        }

        @Override
        public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
            if ((width == 0) || (height == 0)) {
                return;
            }
            if (DEBUG) {
                Log.v(TAG, "surfaceChanged:");
            }
            mPreviewSurfaceInfrared = holder.getSurface();
            synchronized (mSync) {
                if (isActiveInfrared && !isPreviewInfrared && (mUVCCameraInfrared != null)) {
                    mUVCCameraInfrared.setPreviewDisplay(mPreviewSurfaceInfrared);
                    mUVCCameraInfrared.startPreview();
                    isPreviewInfrared = true;
                }
            }
        }

        @Override
        public void surfaceDestroyed(final SurfaceHolder holder) {
            if (DEBUG) Log.v(TAG, "surfaceDestroyed:");
            synchronized (mSync) {
                if (mUVCCameraInfrared != null) {
                    mUVCCameraInfrared.stopPreview();
                }
                isPreviewInfrared = false;
            }
            mPreviewSurfaceInfrared = null;
        }
    };


    /**
     * 关闭线程池，该线程池用于发送心跳包
     */
    private void shutdown() {
        if (mScheduledExecutorService != null) {
            mScheduledExecutorService.shutdown();
            mScheduledExecutorService = null;
        }
    }


//    private void drawFacesArea(FaceDetector.Face[] faces) {
//        Toast.makeText(this, "图片中检测到" + realFaceNum + "张人脸", Toast.LENGTH_SHORT).show();
//        float eyesDistance = 0f;//两眼间距
//        Canvas canvas = new Canvas(tempBitmap);
//        for (int i = 0; i < faces.length; i++) {
//            FaceDetector.Face face = faces[i];
//            if (face != null) {
//                PointF pointF = new PointF();
//                face.getMidPoint(pointF);//获取人脸中心点
//                eyesDistance = face.eyesDistance();//获取人脸两眼的间距
//                //画出人脸的区域
//                canvas.drawRect(pointF.x - eyesDistance, pointF.y - eyesDistance, pointF.x + eyesDistance, pointF.y + eyesDistance, new Paint());
//                hasDetected = true;
//            }
//        }
//        //画出人脸区域后要刷新ImageView
//        tempImage.setImageBitmap(tempBitmap);
//    }


    /**
     * Camera 可見光回调帧
     */
    final Bitmap cameraBitmap = Bitmap.createBitmap(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, Bitmap.Config.RGB_565);
    private final IFrameCallback mIFrameCallback = new IFrameCallback() {

        @Override
        public void onFrame(final ByteBuffer frame) {
            frame.clear();

            Log.d("onFrame", "onFrame: 回调了图像");

            cameraBitmap.copyPixelsFromBuffer(frame);

            // 人脸检测
            FaceDetector faceDetector = new FaceDetector(cameraBitmap.getWidth(), cameraBitmap.getHeight(), 5);
            FaceDetector.Face[] faces = new FaceDetector.Face[5];
            realFaceNum = faceDetector.findFaces(cameraBitmap, faces);

            Log.d("onFrame", "onFrame: 人脸数：" + realFaceNum);

            // 如果图像人脸数大于0
            if (realFaceNum > 0) {

                for (int i = 0; i < faces.length; i++) {
                    FaceDetector.Face face = faces[i];
                    if (face != null) {
                        PointF pointF = new PointF();
                        face.getMidPoint(pointF);//获取人脸中心点
                        eyesDistance = face.eyesDistance();//获取人脸两眼的间距
                        zero = Bitmap.createBitmap(cameraBitmap, (int) (pointF.x - 2 * eyesDistance), (int) (pointF.y - 2 * eyesDistance), (int) (4 * eyesDistance), (int) (4 * eyesDistance));

                        //画出人脸的区域
//                        canvas.drawRect(pointF.x - 2 * eyesDistance, pointF.y - 2 * eyesDistance, pointF.x + 2 * eyesDistance, pointF.y + 2 * eyesDistance, paint);
//                        hasDetected = true;
                    }
                }
                //画出人脸区域后要刷新ImageView
                //tempImage.setImageBitmap(zero);

                if (isReceived) {
                    isReceived = false;
                    synchronized (MainActivitySurface.this) {
                        isVisibleLightPicCollected = true;
                    }
                    // 图片压缩，获取图片的字节流
                    baos = new ByteArrayOutputStream();
                    zero.compress(Bitmap.CompressFormat.JPEG, 20, baos);
                    picBytes = baos.toByteArray();
                }
            }

        }
    };

    /**
     * Camera 紅外回调帧
     */
    final Bitmap cameraBitmapInfrared = Bitmap.createBitmap(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, Bitmap.Config.RGB_565);
    private final IFrameCallback mIFrameCallbackInfrared = new IFrameCallback() {

        @Override
        public void onFrame(final ByteBuffer frame) {
            frame.clear();

            cameraBitmapInfrared.copyPixelsFromBuffer(frame);

            if (isVisibleLightPicCollected) {
                synchronized (MainActivitySurface.this) {
                    isVisibleLightPicCollected = false;
                }
                // 以下代码是将数据写入SDCard，用于测试红外摄像头是否抓取成功
//                File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "twoCameraCrash" + File.separator + count + ".jpg");
//                //文件输出流
//                try {
//                    OutputStream os = new FileOutputStream(file);
//                    cameraBitmapInfrared.compress(Bitmap.CompressFormat.JPEG, 50, os);
//                    Log.d("111", "onMessageResponse: 写入一个红外数据帧:" + count + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));
//                    os.flush();
//                    os.close();
//                    count++;
//                } catch (FileNotFoundException e) {
//                    e.printStackTrace();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }

                baosInfrared = new ByteArrayOutputStream();
                cameraBitmapInfrared.compress(Bitmap.CompressFormat.JPEG, 20, baosInfrared);
                picBytesInfrared = baosInfrared.toByteArray();
                sendPicDataPackage(picBytes, picBytesInfrared);
            }
        }
    };

    /**
     * 隐藏通行提示 UI 的任务类
     */
    private Runnable uiHideRunnable = new Runnable() {
        @Override
        public void run() {
            rlStranger.setVisibility(View.GONE);
            rlSuccess.setVisibility(View.GONE);
        }
    };


    /**
     * 接收服务器的消息
     *
     * @param byteBuf
     */
    @Override
    public void onMessageResponse(ByteBuf byteBuf) {

//        Log.d(TAG, "run: 收到服务器数据时间：" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

        byte[] bytes = byteBuf.array();

        // data.length 原有数据长度，bytes.length 新增数据长度
        byte[] temp = new byte[data.length + byteBuf.readableBytes()];
        // 先将原有数据复制到 中间数组中
        System.arraycopy(data, 0, temp, 0, data.length);
        // 在将新增的数据复制到中间数据中
        System.arraycopy(bytes, 0, temp, data.length, byteBuf.readableBytes());
        // 最终得到数据数组
        data = temp;

//        Log.d("onMessageResponse", "onMessageResponse: 接收数据的次数" + counter++);

        if (data.length >= 28) {

            dataLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();

            // 心跳包
            if (dataLength == 16 && data.length >= dataLength + 12 &&
                    0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    1 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()
                    ) {

//                Log.d("onMessageResponse", "onMessageResponse: 收到心跳包  " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));
                data = ByteUtil.subBytes(data, 28, data.length - 28);
//                Log.d("onMessageResponse: ", "心跳包处理后的数据长度" + data.length);

                // 没有人脸的返回结果
            } else if (dataLength == 80 && data.length >= dataLength + 12 &&
                    0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    0x30 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()
                    ) {

//                Log.d("onMessageResponse", "没有人脸的时间  " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));
//                Log.d(TAG, "onMessageResponse: " + "接收数据---->图片中没有人脸");
//                Log.d(TAG, "没有脸 请求头 key: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 16, 64)).order(ByteOrder.LITTLE_ENDIAN).getLong());
                data = ByteUtil.subBytes(data, dataLength + 12, data.length - dataLength - 12);

//                Log.d("onMessageResponse", "onMessageResponse: 没脸，处理完毕" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));
//                Log.d("onMessageResponse: ", "没脸数据包处理后的长度" + data.length);
                isReceived = true;

                // 有人脸的返回结果
            } else {

                // 当数据长度或等于一个数据包的长度时，才截断出一个完整的数据包
                if (data.length >= dataLength + 12) {

//                    Log.d("onMessageResponse", "onMessageResponse: 拼接数据长度" + data.length);
//                    Log.d("onMessageResponse", "onMessageResponse: 数据包长度" + (dataLength + 12));
//
//                    Log.d("onMessageResponse", "onMessageResponse: 有脸，接收完毕" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                    // 人像比对分数超过 50 ,则验证通过
                    if (ByteBuffer.wrap(ByteUtil.subBytes(data, 344, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat() > 50) {

                        Log.d("onMessageResponse", "验证通过时间  " + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                        isStart = true;

                        //图片字节长度
                        int picLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();

                        byte[] picByte = ByteUtil.subBytes(data, 352, picLength);

                        receiveBitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);

                        // 姓名
                        personNameByte = ByteUtil.subBytes(data, 112, 40);
                        for (int i = 0; i < personNameByte.length; i++) {
                            if (personNameByte[i] == 0) {
                                personNameIndex = i;
                                break;
                            }
                        }

                        // 截取人员 ID
                        personIDByte = ByteUtil.subBytes(data, 92, 20);
                        for (int i = 0; i < personIDByte.length; i++) {
                            if (personIDByte[i] == 0) {
                                personIdIndex = i;
                                break;
                            }
                        }

                        if (!personIdList.contains(new String(ByteUtil.subBytes(personIDByte, 0, personIdIndex)))) {

                            personIdList.add(new String(ByteUtil.subBytes(personIDByte, 0, personIdIndex)));

                            // 语音停止播放
                            mTts.stopSpeaking();
                            handler.removeCallbacks(uiHideRunnable);
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    // 如果新人进入通道且验证通过，则立刻关闭之前的 UI ，显示新的 UI
                                    //handler.obtainMessage(UI_HIDE).sendToTarget();

                                    // 给 UI 控件设置新人数据
                                    mImageView.setImageBitmap(receiveBitmap);
                                    tvNameResult.setText(new String(ByteUtil.subBytes(personNameByte, 0, personNameIndex)));
                                    tvIdResult.setText(new String(ByteUtil.subBytes(personIDByte, 0, personIdIndex)));

                                    rlStranger.setVisibility(View.GONE);
                                    rlSuccess.setVisibility(View.VISIBLE);

                                    handler.postDelayed(uiHideRunnable, 3000);

                                    byte[] openCardId = CRC16M.getSendBuf("0000000000000001");
                                    byte openAccessMode = Byte.parseByte("05");
                                    DoorAccessCommManager.getInstance().sendLongOpenCommand(openCardId, openAccessMode);

                                    handler.postDelayed(new Runnable() {
                                        @Override
                                        public void run() {
                                            byte[] closeCardId = CRC16M.getSendBuf("0000000000000001");
                                            byte closeAccessMode = Byte.parseByte("02");
                                            //DoorAccessCommManager.getInstance().sendCloseCommand(closeCardId, closeAccessMode);
                                            GpioController.getInstance().lockGate();
                                        }
                                    }, 1000);
                                }
                            });

                            // 播放通行提示语音
                            voicePlay(true);

                            // 打开闸机通道门
                            //GPIOController.getInstance().open();
                            GpioController.getInstance().unLockGate();
                        }

                    } else {

                        if (isStart) {
                            isStart = false;
                            startTime = System.currentTimeMillis();
                        } else {
                            endTime = System.currentTimeMillis();
                        }

                        Log.d("time", "时间差值: " + (endTime - startTime));

                        // 验证失败持续4秒，才显示失败提示 UI
                        if (endTime - startTime > 4000) {

                            isStart = true;

                            voicePlay(false);

                            handler.removeCallbacks(uiHideRunnable);

                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    rlStranger.setVisibility(View.VISIBLE);
                                    rlSuccess.setVisibility(View.GONE);
                                }
                            });

                            handler.postDelayed(uiHideRunnable, 3000);
                        }
                    }


//                    Log.d(TAG, "onMessageResponse:收到数据包长度 " + data.length);
//                    Log.d(TAG, "onMessageResponse 请求头: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
//                    Log.d(TAG, "onMessageResponse: 拼接数据长度 if " + data.length);
//                    Log.d(TAG, "onMessageResponse 数据长度: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
//                    Log.d(TAG, "onMessageResponse 请求类型: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 8, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
//                    Log.d(TAG, "onMessageResponse 请求 enumType: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 12, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
//                    Log.d(TAG, "onMessageResponse 请求头 key: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 16, 64)).order(ByteOrder.LITTLE_ENDIAN).getLong());
//                    Log.d(TAG, "onMessageResponse 请求头结果，“0”代表验证失败,“1”代表验证成功 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 80, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
//                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 84, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
//                    Log.d(TAG, "onMessageResponse 结果数目 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 88, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());


//                    BigInteger bigInteger = new BigInteger(ByteUtil.subBytes(data, 152, 64));
//                    long longValue = bigInteger.longValue();
//                    Log.d(TAG, "onMessageResponse 时间: " + DateFormatUtil.format(longValue, DateFormatUtil.DateFormatEnum.ymdhms));
//                    Log.d(TAG, "onMessageResponse 点位 : " + ByteUtil.subBytes(data, 216, 128));
//                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 344, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
//                    Log.d(TAG, "onMessageResponse 注册图片长度 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());

                    data = ByteUtil.subBytes(data, dataLength + 12, data.length - dataLength - 12);
//                    Log.d("onMessageResponse: ", "有脸数据包处理后的长度" + data.length);
//                    Log.d("onMessageResponse", "onMessageResponse: 有脸，处理完毕" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));
//                    处理完一个数据包，才会去发送新的一帧数据
                    isReceived = true;
                }
            }
        }
    }

    /**
     * 人体红外检测中断值，当检测到人体时，Activity onKeyDown 回调定时收到此键码，检测不到人时则停止发送
     * 禁止返回键
     *
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.d("keyCode", "keyCode:" + keyCode);

        //一旦有红外信号触发，就重置系统启动初始时间
        systemStartRunTime = System.currentTimeMillis();

        if (keyCode == DoorAccessCommManager.KEYCODE_INFRARED_ON) {
//            openLight(LedLightManager.LED_LIGHT_0);
//            openLight(LedLightManager.LED_LIGHT_1);
            GpioController.getInstance().turnOnLed();
        }

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    /**
     * 和服务器的连接状态发生改变
     *
     * @param statusCode
     */
    @Override
    public void onServiceStatusConnectChanged(int statusCode) {
        Timber.d("connect status:%d", statusCode);
        if (statusCode == NettyListener.STATUS_CONNECT_SUCCESS) {

            // 连接成功
            handler.post(new Runnable() {
                @Override
                public void run() {
                    rlNetError.setVisibility(View.GONE);
                }
            });

            sendHeatBeatPackage();
            isReceived = true;
            data = new byte[0];

            Log.d("NettyClient", "onServiceStatusConnectChanged: 连接成功");

        } else if (statusCode == NettyListener.STATUS_CONNECT_CLOSED) {
            // 连接关闭
            handler.post(new Runnable() {
                @Override
                public void run() {
                    rlNetError.setVisibility(View.VISIBLE);
                }
            });
            Log.d("NettyClient", "onServiceStatusConnectChanged: 连接失败");

        } else if (statusCode == NettyListener.STATUS_CONNECT_ERROR) {
            // 连接出错
            WriteLogUtil.writeLogByThread("tcp connect error");
            handler.post(new Runnable() {
                @Override
                public void run() {
                    rlNetError.setVisibility(View.VISIBLE);
                }
            });
        }
    }


    /**
     * 连接到服务器，未
     */
    private void connect() {
        if (!NettyClient.getInstance().getConnectStatus()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //连接服务器
                    NettyClient.getInstance().connect();
                }
            }).start();
        }
    }

    /**
     * 发送图片数据包
     */
    public void sendPicDataPackage(final byte[] picBytes, byte[] picBytesInfrared) {

        picDataBytes = ArrayMergeUtil.byteMergerAll(

                // 以下三条为请求头部分
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 表示数据包的长度，只是数据，不包含头
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picBytes.length + picBytesInfrared.length + 916)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 数据包的类型 0x30
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.DATA_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                //============================================ 以下为真正的数据包 =================================================================
                // 标识请求的哪一个比对服务
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.ENUM_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 64 字节key，确保请求的唯一性
                //TcpAssembleUtil.assembleRequestKey(),
                ByteUtil.putLong(System.currentTimeMillis(), 0),
                //  20个字节的0
                TcpAssembleUtil.assembleRequestId(),
                // 请求优先级,
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PRIORITY)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 阈值
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_THRESHOLD)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 最大结果数
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_TOP_X)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                // 图片的张数
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PIC_NUM)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 可见光图片的长度，需动态计算
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picBytes.length)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 红外图片长度
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picBytesInfrared.length)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 有几张脸，暂时为 0
                NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_FACE_COUNT)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                // 50结构体，每个结构体有4个int
                TcpAssembleUtil.assembleStruct(),

                // 图片数据
                picBytes,

                picBytesInfrared

        );

        NettyClient.getInstance().sendMsgToServer(picDataBytes, new ChannelFutureListener() {    //3
            @Override
            public void operationComplete(ChannelFuture future) {
                if (future.isSuccess()) {                //4
                    Timber.d("Write heartbeat successful");

                } else {
                    Timber.e("Write heartbeat error");
                    WriteLogUtil.writeLogByThread("heartbeat error");
                }
            }
        });

        picDataBytes = null;
    }

    /**
     * 初始化监听。
     */
    private InitListener mTtsInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
            Log.d(TAG, "InitListener init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                Toast.makeText(MainActivitySurface.this, "初始化失败,错误码：" + code, Toast.LENGTH_SHORT).show();
            } else {
                // 初始化成功，之后可以调用startSpeaking方法
                // 注：有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成，
                // 正确的做法是将onCreate中的startSpeaking调用移至这里

            }
        }
    };

    /**
     * 语音合成及播放
     */
    public void voicePlay(boolean isSuccess) {
        Log.d(TAG, "voicePlay: ");
        String text;
        if (isSuccess) {
            Random ra = new Random();
            int index = ra.nextInt(contentList.size());
            text = contentList.get(index);
        } else {
            text = "认证失败";
        }

        // 设置参数
        setParam();
        int code = mTts.startSpeaking(text, mTtsListener);
//			/**
//			 * 只保存音频不进行播放接口,调用此接口请注释startSpeaking接口
//			 * text:要合成的文本，uri:需要保存的音频全路径，listener:回调接口
//			*/
//			String path = Environment.getExternalStorageDirectory()+"/tts.pcm";
//			int code = mTts.synthesizeToUri(text, path, mTtsListener);

        if (code != ErrorCode.SUCCESS) {
            Toast.makeText(this, "语音合成失败,错误码: " + code, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 参数设置
     *
     * @return
     */
    private void setParam() {


        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);

        //设置合成
//        if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) {
//            //设置使用云端引擎
//            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
//            //设置发音人
//            mTts.setParameter(SpeechConstant.VOICE_NAME, voicerCloud);
//        } else {
        //设置使用本地引擎
        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
        //设置发音人资源路径
        mTts.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath());
        //设置发音人
        if (SPUtils.getSharedStringData("VOICE_NAME") != null) {
            mTts.setParameter(SpeechConstant.VOICE_NAME, SPUtils.getSharedStringData("VOICE_NAME"));
        } else {
            mTts.setParameter(SpeechConstant.VOICE_NAME, voicerLocal);
        }
//        }
        //设置合成语速
        if (SPUtils.getSharedStringData("SPEED") != null) {
            mTts.setParameter(SpeechConstant.SPEED, SPUtils.getSharedStringData("SPEED"));
        } else {
            mTts.setParameter(SpeechConstant.SPEED, "50");
        }
        //设置合成音调
        if (SPUtils.getSharedStringData("PITCH") != null) {
            mTts.setParameter(SpeechConstant.PITCH, SPUtils.getSharedStringData("PITCH"));
        } else {
            mTts.setParameter(SpeechConstant.PITCH, "50");
        }
        //设置合成音量
        if (SPUtils.getSharedStringData("VOLUME") != null) {
            mTts.setParameter(SpeechConstant.VOLUME, SPUtils.getSharedStringData("VOLUME"));
        } else {
            mTts.setParameter(SpeechConstant.VOLUME, "50");
        }

        //设置播放器音频流类型
        mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");

        // 设置播放合成音频打断音乐播放，默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 设置音频保存路径，保存音频格式支持pcm、wav，设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注：AUDIO_FORMAT 参数语记需要更新版本才能生效
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts.wav");
    }

    /**
     * 获取发音人资源路径
     */
    private String getResourcePath() {
        StringBuffer tempBuffer = new StringBuffer();
        //合成通用资源
        tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "tts/common.jet"));
        tempBuffer.append(";");
        //发音人资源
        tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "tts/" + MainActivitySurface.voicerLocal + ".jet"));
        return tempBuffer.toString();
    }

    /**
     * 合成回调监听。
     */
    private SynthesizerListener mTtsListener = new SynthesizerListener() {

        @Override
        public void onSpeakBegin() {
            //Toast.makeText(MainActivitySurface.this, "开始播放", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "onSpeakBegin: ");
        }

        @Override
        public void onSpeakPaused() {
            //Toast.makeText(MainActivitySurface.this, "暂停播放", Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onSpeakResumed() {
            //Toast.makeText(MainActivitySurface.this, "继续播放", Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
            // 合成进度
            mPercentForBuffering = percent;
            Log.d(TAG, "onBufferProgress: " + percent);
            //showTip(String.format(getString(R.string.tts_toast_format), mPercentForBuffering, mPercentForPlaying));
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            // 播放进度
            mPercentForPlaying = percent;
            //showTip(String.format(getString(R.string.tts_toast_format), mPercentForBuffering, mPercentForPlaying));

            SpannableStringBuilder style = new SpannableStringBuilder(texts);
            Log.e(TAG, "beginPos = " + beginPos + "  endPos = " + endPos);
            //富文本，将正在读的语音标红
//            if (!"henry".equals(voicerCloud) || !"xiaoyan".equals(voicerCloud) || !"xiaoyu".equals(voicerCloud) || !"catherine".equals(voicerCloud)) {
//                endPos++;
//            }
//            style.setSpan(new BackgroundColorSpan(Color.RED), beginPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//            ((EditText) findViewById(R.id.tts_text)).setText(style);
        }

        @Override
        public void onCompleted(SpeechError error) {
//            if (error == null) {
//                showTip("播放完成");
//            } else if (error != null) {
//                showTip(error.getPlainDescription(true));
//            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id，当业务出错时将会话id提供给技术支持人员，可用于查询会话日志，定位出错原因
            // 若使用本地能力，会话id为null
            //	if (SpeechEvent.EVENT_SESSION_ID == eventType) {
            //		String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
            //		Log.d(TAG, "session id =" + sid);
            //	}
        }
    };

}
